﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Net;
using System.Net.Mail;

namespace EmailSender
{
    public class SmtpSender : IRichMessageEmailSender, IEmailSender
    {
        private readonly NetworkCredential _credentials = new NetworkCredential();
        private readonly string _hostname;
        private readonly SmtpClient _smtpClient;
        private bool _asyncSend;
        private bool _configured;
        private int _port = 0x19;

        public SmtpSender(string hostname)
        {
            _hostname = hostname;
            _smtpClient = new SmtpClient(hostname);
        }

        public bool AsyncSend
        {
            get { return _asyncSend; }
            set { _asyncSend = value; }
        }

        public string Domain
        {
            get { return _credentials.Domain; }
            set { _credentials.Domain = value; }
        }

        public bool EnableSsl { get; set; }

        protected bool HasCredentials
        {
            get { return ((_credentials.UserName != null) && (_credentials.Password != null)); }
        }

        public string Hostname
        {
            get { return _hostname; }
        }

        public string Password
        {
            get { return _credentials.Password; }
            set { _credentials.Password = value; }
        }

        public int Port
        {
            get { return _port; }
            set { _port = value; }
        }

        public int Timeout
        {
            get { return _smtpClient.Timeout; }
            set { _smtpClient.Timeout = value; }
        }

        public string UserName
        {
            get { return _credentials.UserName; }
            set { _credentials.UserName = value; }
        }

        #region IRichMessageEmailSender Members

        public void Send(Message[] messages)
        {
            foreach (Message message in messages)
            {
                Send(message);
            }
        }

        public void Send(Message message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            ConfigureSender(message);
            if (_asyncSend)
            {
                MailMessage msg = CreateMailMessage(message);
                var msgGuid = new Guid();
                SendCompletedEventHandler sceh = null;
                sceh = delegate(object sender, AsyncCompletedEventArgs e)
                           {
                               if (msgGuid == ((Guid) e.UserState))
                               {
                                   msg.Dispose();
                               }
                               _smtpClient.SendCompleted -= sceh;
                           };
                _smtpClient.SendCompleted += sceh;
                _smtpClient.SendAsync(msg, msgGuid);
            }
            else
            {
                using (MailMessage message2 = CreateMailMessage(message))
                {
                    _smtpClient.Send(message2);
                }
            }
        }

        public void Send(string from, string to, string subject, string messageText)
        {
            if (from == null)
            {
                throw new ArgumentNullException("from");
            }
            if (to == null)
            {
                throw new ArgumentNullException("to");
            }
            if (subject == null)
            {
                throw new ArgumentNullException("subject");
            }
            if (messageText == null)
            {
                throw new ArgumentNullException("messageText");
            }
            Send(new Message(from, to, subject, messageText));
        }

        #endregion

        protected virtual void ConfigureSender(Message message)
        {
            if (!_configured)
            {
                if (HasCredentials)
                {
                    _smtpClient.Credentials = _credentials;
                }
                _smtpClient.Port = _port;
                _smtpClient.EnableSsl = EnableSsl;
                _configured = true;
            }
        }

        private static MailMessage CreateMailMessage(Message message)
        {
            var message2 = new MailMessage(message.From, message.To.Replace(';', ','));
            if (!string.IsNullOrEmpty(message.Cc))
            {
                message2.CC.Add(message.Cc);
            }
            if (!string.IsNullOrEmpty(message.Bcc))
            {
                message2.Bcc.Add(message.Bcc);
            }
            message2.Subject = message.Subject;
            message2.Body = message.Body;
            message2.BodyEncoding = message.Encoding;
            message2.IsBodyHtml = message.Format == Format.Html;
            message2.Priority = (MailPriority) Enum.Parse(typeof (MailPriority), message.Priority.ToString());
            message2.ReplyTo = message.ReplyTo;
            foreach (DictionaryEntry entry in message.Headers)
            {
                message2.Headers.Add((string) entry.Key, (string) entry.Value);
            }
            foreach (MessageAttachment attachment in message.Attachments)
            {
                Attachment attachment2;

                attachment2 = new Attachment(attachment.FileName);

                message2.Attachments.Add(attachment2);
            }
            if ((message.Resources != null) && (message.Resources.Count > 0))
            {
                AlternateView item = AlternateView.CreateAlternateViewFromString(message.Body, message.Encoding,
                                                                                 "text/html");
                foreach (string str in message.Resources.Keys)
                {
                    LinkedResource resource = message.Resources[str];
                    resource.ContentId = str;
                    if (resource.ContentStream != null)
                    {
                        item.LinkedResources.Add(resource);
                    }
                }
                message2.AlternateViews.Add(item);
            }
            return message2;
        }
    }
}